﻿// TestMain.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <host.h>
#ifdef WIN32
#include <shlwapi.h>
#include <strsafe.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#endif

#include "TestBasic.h"
#include "G722Decode.h"
#include "MediaPaser.h"
//#include "resampler.h"
#include "AudioData.c"

#ifdef WIN32
#pragma comment(lib,"shlwapi.lib")
#pragma comment(lib, "Mfplat.lib")
#pragma comment(lib, "Mf.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")
#endif

#define G722_ENCODED_FRAME_SIZE      80
#define G722_DECODED_FRAME_SIZE      160

using namespace host;


static void SavePicture(const char * sPath, unsigned char* i_pFrameData, unsigned int i_u32Len)
{
    FILE *fOut = NULL;

    OSCon::Print("Got one Frame Write to file<%s>\n", sPath);

    fOut = fopen(sPath, "wb");
    fwrite(i_pFrameData, 1, i_u32Len, fOut);
    fflush(fOut);
    fclose(fOut);
}

TESTUNIT(G722FileDecode, 1, "G722FileDecode <input file>")
{
    G722Decode decoder;

    decoder.Init();

    FILE *audio = fopen(".\\130.g722", "rb");
    FILE *output = fopen(".\\130_o.pcm", "wb");
    unsigned char  buffer[160];
      signed short pcm[320];
    unsigned int   loop = 0;
    while (fread(buffer, 1, G722_ENCODED_FRAME_SIZE, audio) == G722_ENCODED_FRAME_SIZE)
    {
        if (loop++ % 12 == 0)
        {
            decoder.Decode(buffer, G722_ENCODED_FRAME_SIZE, pcm);
            fwrite(pcm, G722_DECODED_FRAME_SIZE, sizeof(short), output);
        }
    }

    fclose(audio);
    fclose(output);

    return true;
}


TESTUNIT(G722PcapPaser, 1, "G722PcapPaser <input file> [chan=2]")
{
    const char *inPath = args[0];
    int chan = 2;
    string outPath;
    string sFolder = "";
    string sName = "";

    if (argc >= 2)
    {
        chan = atoi(args[1]);
    }

    OSFile::Cover2Folder(inPath, sFolder);
    OSFile::Mkdir(sFolder.c_str());

    NetRTP rtpPcap;
    rtpPcap.Open(inPath);
    if (rtpPcap.IsOpen() == false)
    {
        OSCon::PrintR("open pcap failed");
        return -1;
    }

    G722Decode decoder[2];

    decoder[0].Init();
    decoder[1].Init();

    outPath = sFolder + "\\out.wav";
    struct RTPPacket* pRtpPkt = NULL;
    WavFile wavFile;
    wavFile.Create(outPath.c_str(), 16000, 2, 16);

    int          nPktLen = 0;
    unsigned int nFrames = 0;
    UInt16       u16LastSeq = 0;
    UInt32       u32PacketNum = 0;
    while (true)
    {
        nPktLen = rtpPcap.Next(pRtpPkt);
        if (nPktLen < 0) //EOF
            break;
        if (nPktLen == 0) //Not is RTP
            continue;

        unsigned char* pData = NULL;
        UInt32 u32ExtLen = 0;
        UInt32 u32PaylaodLen = 0;
        UInt32 u32FrameLen = G722_ENCODED_FRAME_SIZE * chan;
        UInt32 u32FrameNum = 1;
        UInt16 u16Seq = OS::Ntohs(pRtpPkt->sequence);
        UInt16 u16LossCnt = u16Seq - u16LastSeq;

        u32PacketNum++;
        if (u32PacketNum == 1)
            u16LossCnt = 1;
        if (pRtpPkt->vpxcc & 0x10)
        {
            u32ExtLen += sizeof(UInt32);
            u32ExtLen += OS::Ntohs(*(UInt16*)(pRtpPkt->payload + 2)) * sizeof(UInt32);
        }
        pData = pRtpPkt->payload + u32ExtLen;
        u32PaylaodLen = nPktLen - (RTP_HEAD_SIZE + u32ExtLen);
        u32FrameNum = u32PaylaodLen / u32FrameLen;
        if(u16LossCnt == 0) //repeat
            continue;

        UInt8* pEncBuf[2] = { NULL };
        SInt16 acPcmBuf[2][G722_DECODED_FRAME_SIZE] = { { 0 } };
        SInt16 acInterlace[2 * G722_DECODED_FRAME_SIZE] = { 0 };
        //packet list: N N-1 N-2 N-3 ....
        for (decltype(u32FrameNum) i = 0; i < u16LossCnt && i < u32FrameNum; i++)
        {
            if (u16LossCnt == 1) //not loss, decode the first frame
            {
                pEncBuf[0] = (UInt8*)pData;
                pEncBuf[1] = (UInt8*)pData + (chan == 2 ? G722_ENCODED_FRAME_SIZE : 0);
            }
            else //loss, decode the last frame first
            {
                pEncBuf[0] = (UInt8*)pData + G722_ENCODED_FRAME_SIZE * (u32FrameNum - i - 1) * 2;
                pEncBuf[1] = (UInt8*)pData + G722_ENCODED_FRAME_SIZE * (u32FrameNum - i - 1) * 2 + (chan == 2 ? G722_ENCODED_FRAME_SIZE : 0);
            }
            decoder[0].Decode(pEncBuf[0], G722_ENCODED_FRAME_SIZE, acPcmBuf[0]);
            decoder[1].Decode(pEncBuf[1], G722_ENCODED_FRAME_SIZE, acPcmBuf[1]);
            for (int k = 0; k < G722_DECODED_FRAME_SIZE; k++)
            {
                acInterlace[2 * k + 0] = acPcmBuf[0][k];
                acInterlace[2 * k + 1] = acPcmBuf[1][k];
            }
            wavFile.Write((UInt8*)acInterlace, G722_DECODED_FRAME_SIZE * 2 * sizeof(SInt16));
        }
        u16LastSeq = u16Seq;
    }

    rtpPcap.Close();
    wavFile.Close();

    return true;
}

TESTUNIT(CameraParser,1 ,"CameraPaser <input file>")
{
    string inPath = args[0];
    string inFull;
    string outPath;
    string sFolder = "";
    string sName = "";

    OSFile::PathFix(inPath);
    if (!OSFile::IsExist(inPath.c_str()))
    {
        OSCon::PrintY("file[%s] is not exist", inPath.c_str());
        return -EINVAL;
    }

    OSFile::GetSuffix(inPath.c_str(), sName);
    if (sName != "pcap" && sName != "pcapng")
    {
        OSCon::PrintY("file[%s] is not vaild pcap file", inPath.c_str());
        return -EINVAL;
    }

    OSFile::GetName(inPath.c_str(), sName);
    OSFile::GetFullPath(inPath.c_str(), inFull);
    OSFile::GetFolder(inFull.c_str(), sFolder);

    sFolder += "\\" + sName;
    OSFile::Mkdir(sFolder.c_str());

    AviFile aviFile;
    outPath = sFolder + "\\video.avi";
    aviFile.SetVenc(1280, 720, 10);
    aviFile.Create(outPath.c_str(), true, false);

    NetVideo videoPcap;
    videoPcap.Open(inPath.c_str());
    if (videoPcap.IsOpen() == false)
    {
        OSCon::PrintR("open pcap failed\n");
        return -1;
    }

    CMediaParser::Init();

    struct RTPPacket *pVideoPkt = NULL;

    char         sPath[512] = "";
    int          nPktLen = 0;
    unsigned int nFrames = 0;
    while (true)
    {
        nPktLen = videoPcap.Next(pVideoPkt);
        if (nPktLen < 0) //EOF
            break;
        if (nPktLen == 0) //Not is RTP
            continue;

        //OSCon::Print("nPktLen:%u seq:%hu\n", nPktLen, OS::Ntohs(pVideoPkt->sequence), pVideoPkt->ptype);
        char *pData = NULL;
        TRtpDataInfo *tRtpData;
        UInt32 u32FrameLen;

        tRtpData = CMediaParser::GetBuffer();
        if (tRtpData == NULL)
        {
            OSCon::Print("Error: GetBuffer is NULL\n");
            continue;
        }

        memcpy(tRtpData->acRtpData, pVideoPkt, nPktLen);
        tRtpData->u32RtpDataLen = nPktLen;

        if (!CMediaParser::VideoRtpPacketParse(tRtpData, &pData, u32FrameLen))
            continue;

        aviFile.WriteVideo((unsigned char*)pData, u32FrameLen, 0);
        sprintf(sPath, "%s\\Frame-%02d.jpg", sFolder.c_str(), nFrames++);
        SavePicture(sPath, (unsigned char*)pData, u32FrameLen);
    }

    aviFile.WriteTail();
    aviFile.Close();
    videoPcap.Close();
    CMediaParser::Destroy();

    return true;
}

TESTUNIT(UsbAudioPaser, 1, "UsbAudioPaser <input file>")
{
    string inPath = args[0];
    string inFull;
    string outPath;
    string sFolder = "";
    string sName = "";

    OSFile::PathFix(inPath);
    if (!OSFile::IsExist(inPath.c_str()))
    {
        OSCon::PrintY("file[%s] is not exist", inPath.c_str());
        return -EINVAL;
    }

    OSFile::GetSuffix(inPath.c_str(), sName);
    if (sName != "pcap" && sName != "pcapng")
    {
        OSCon::PrintY("file[%s] is not vaild pcap file", inPath.c_str());
        return -EINVAL;
    }

    OSFile::GetName(inPath.c_str(), sName);
    OSFile::GetFullPath(inPath.c_str(), inFull);
    OSFile::GetFolder(inFull.c_str(), sFolder);

    sFolder += sName;
    OSFile::Mkdir(sFolder.c_str());

    NetUsbAudio uacPcap;
    uacPcap.Open(inFull.c_str());
    if (uacPcap.IsOpen() == false)
    {
        OSCon::PrintR("open pcap failed\n");
        return -1;
    }

    outPath = sFolder + "\\out.pcm";
    struct URBPacket *pUrbPkt = NULL;
    FILE* outFile = fopen(outPath.c_str(), "wb");

    int          nPktLen = 0;
    unsigned int nFrames = 0;
    while (true)
    {
        nPktLen = uacPcap.Next(pUrbPkt);
        if (nPktLen < 0) //EOF
            break;
        if (nPktLen == 0) //Not is RTP
            continue;

        //OSCon::Print("nPktLen:%u seq:%hu\n", nPktLen, OS::Ntohs(pVideoPkt->sequence), pVideoPkt->ptype);
        unsigned char *pData = NULL;
//        TRtpDataInfo *tRtpData;
        UInt32 u32FrameLen;

        pData = pUrbPkt->payload + 12 * pUrbPkt->pakcet_number;
        u32FrameLen = pUrbPkt->data_length;

        fwrite(pData, 1, u32FrameLen, outFile);
    }

    uacPcap.Close();
    fclose(outFile);

    return 0;
}

TESTUNIT(NetAudioPaser, 1, "NetAudioPaser <input file>")
{
    string inPath = args[0];
    string inFull;
    string outPath;
    string sFolder = "";
    string sName = "";

    OSFile::PathFix(inPath);
    if (!OSFile::IsExist(inPath.c_str()))
    {
        OSCon::PrintY("file[%s] is not exist", inPath.c_str());
        return -EINVAL;
    }

    OSFile::Cover2Folder(args[0], sFolder);
    OSFile::Mkdir(sFolder.c_str());

    NetUDP UdpPcap;
    UdpPcap.Open(inPath.c_str());
    if (UdpPcap.IsOpen() == false)
    {
        OSCon::PrintR("open pcap failed\n");
        return -1;
    }

    outPath = sFolder + "\\out.wav";
    struct UDPPacket* pUdpPkt = NULL;
    WavFile wavFile;
    wavFile.Create(outPath.c_str(), 16000, 1, 16);

    int          nPktLen = 0;
    unsigned int nFrames = 0;
    while (true)
    {
        nPktLen = UdpPcap.Next(pUdpPkt);
        if (nPktLen < 0) //EOF
            break;
        if (nPktLen == 0) //Not is RTP
            continue;

        //OSCon::Print("nPktLen:%u seq:%hu\n", nPktLen, OS::Ntohs(pVideoPkt->sequence), pVideoPkt->ptype);
        unsigned char* pData = NULL;
        UInt32 u32FrameLen;

        pData = pUdpPkt->payload;
        u32FrameLen = OS::Ntohs(pUdpPkt->length) - UDP_HEAD_SIZE;

        wavFile.Write(pData, u32FrameLen);
    }

    UdpPcap.Close();
    wavFile.Close();

    return 0;
}

TESTUNIT(NetSpeakerPaser, 1, "NetSpeakerPaser <input file>")
{
    string inPath = args[0];
    string inFull;
    string outPath;
    string sFolder = "";
    string sName = "";

    OSFile::PathFix(inPath);
    if (!OSFile::IsExist(inPath.c_str()))
    {
        OSCon::PrintY("file[%s] is not exist", inPath.c_str());
        return -EINVAL;
    }

    OSFile::Cover2Folder(args[0], sFolder);
    OSFile::Mkdir(sFolder.c_str());

    NetRTP rtpPcap;
    rtpPcap.Open(inPath.c_str());
    if (rtpPcap.IsOpen() == false)
    {
        OSCon::PrintR("open pcap failed\n");
        return -1;
    }

    outPath = sFolder + "\\out.wav";
    struct RTPPacket* pRtpPkt = NULL;
    WavFile wavFile;
    wavFile.Create(outPath.c_str(), 48000, 2, 16);

    int          nPktLen = 0;
    unsigned int nFrames = 0;
    while (true)
    {
        nPktLen = rtpPcap.Next(pRtpPkt);
        if (nPktLen < 0) //EOF
            break;
        if (nPktLen == 0) //Not is RTP
            continue;

        unsigned char* pData = NULL;
        UInt32 u32ExtLen = 0;
        UInt32 u32PaylaodLen = 0;

        if (pRtpPkt->vpxcc & 0x10)
        {
            u32ExtLen += sizeof(UInt32);
            u32ExtLen += OS::Ntohs(*(UInt16*)(pRtpPkt->payload + 2)) * sizeof(UInt32);
        }

        pData = pRtpPkt->payload + u32ExtLen;
        u32PaylaodLen = nPktLen - (RTP_HEAD_SIZE + u32ExtLen);

        if(u32PaylaodLen > 0)
            wavFile.Write(pData, u32PaylaodLen);
    }

    rtpPcap.Close();
    wavFile.Close();

    return 0;
}

TESTUNIT(GenHdcpKey, 0, "GenHdcpKey <input file>")
{
    const unsigned char key[] =
    {
        0xB5, 0x9E, 0x6E, 0x54, 0x02, 0x9D, 0xAB, 0x0A, 0x5D, 0x11, 0xBC, 0xC3, 0x0C, 0x22, 0x45, 0xB7,
        0x9A, 0x0C, 0xD1, 0x6A, 0x61, 0xBB, 0xFA, 0xA4, 0xC4, 0x5C, 0x94, 0xF4, 0x08, 0x58, 0x25, 0xBF,
        0x91, 0xE0, 0x6A, 0x1A, 0x21, 0x25, 0xDA, 0x14, 0xC4, 0x1C, 0x86, 0x17, 0x9A, 0xAC, 0x06, 0x9D,
        0x6C, 0x3D, 0x1B, 0x7D, 0x77, 0x08, 0x0F, 0xF0, 0x44, 0x27, 0x5B, 0x63, 0x86, 0xAA, 0x18, 0x98,
        0x9D, 0xB5, 0x68, 0x6E, 0xA9, 0xE5, 0xD3, 0x45, 0xC6, 0x89, 0xD6, 0x82, 0xAD, 0x03, 0x3D, 0x9D,
        0x09, 0x5A, 0xD2, 0xC4, 0x28, 0xDA, 0x42, 0x4F, 0x59, 0x98, 0x68, 0x52, 0xFA, 0xF1, 0x51, 0xC6,
        0x26, 0x1B, 0xB7, 0x02, 0xA8, 0x63, 0x78, 0xFE, 0x4B, 0x58, 0x0E, 0x41, 0x3E, 0x5B, 0x54, 0x61,
        0xA3, 0x50, 0x4F, 0x44, 0x75, 0xE3, 0x77, 0x60, 0xD7, 0x69, 0xC4, 0x2E, 0xC3, 0x5A, 0x76, 0x04,
        0x7A, 0xF0, 0x87, 0xEA, 0xFF, 0xBD, 0xD5, 0x57, 0x53, 0xDA, 0xC4, 0x31, 0x55, 0xE4, 0x9C, 0xBE,
        0x43, 0xE7, 0x16, 0xE0, 0x09, 0xE6, 0x83, 0xDB, 0x4D, 0x17, 0x07, 0xD1, 0xDC, 0xF1, 0x24, 0xD7,
        0x62, 0xC8, 0xC4, 0x9B, 0x82, 0x2C, 0xDC, 0x00, 0xFB, 0x42, 0xF6, 0xEC, 0x93, 0x2F, 0xCB, 0x3B,
        0xFC, 0x3B, 0x43, 0x28, 0xED, 0xD1, 0x67, 0x72, 0xE9, 0x19, 0xB7, 0x09, 0x08, 0xF9, 0xE0, 0x9C,
        0x93, 0xB6, 0x07, 0x43, 0xFF, 0x8E, 0x0A, 0xBB, 0x06, 0x5D, 0xCE, 0x8D, 0xC5, 0xEF, 0xF0, 0x35,
        0xD0, 0xA2, 0xA2, 0xD5, 0x8D, 0x82, 0xD2, 0x18, 0x76, 0x56, 0xEA, 0x18, 0xF5, 0xBD, 0xB7, 0x1F,
        0xDF, 0xF3, 0x64, 0xFF, 0xBC, 0xC8, 0xF3, 0xC9, 0x95, 0x62, 0xB0, 0x83, 0x22, 0x5E, 0x2C, 0x28,
        0x1D, 0xC2, 0xCF, 0x68, 0x0F, 0x1B, 0x58, 0xBB, 0x18, 0x68, 0xCB, 0x0F, 0xB0, 0xC2, 0x7C, 0xB4,
        0x85, 0x77, 0x12, 0x10, 0xF8, 0xBE, 0x1D, 0x36, 0xBE, 0x14, 0xF0, 0x47, 0xF0, 0x8A, 0xDA, 0x89,
        0x99, 0x89, 0xEE, 0x2F, 0xDE, 0xA2, 0x7F, 0x45, 0x3A, 0x6D, 0x1A, 0xBA, 0x3F, 0xF4, 0xFF, 0xFF
    };
    unsigned int addr = 0x006000;

    OSCon::Print("56 FF 80 00");
    OSCon::Print("56 EE 01 00");
    OSCon::Print("56 FF 90 00");
    OSCon::Print("56 02 df 00");
    OSCon::Print("56 02 ff 00");
    OSCon::Print("56 FF 80 00");
    OSCon::Print("56 5a 86 00");
    OSCon::Print("56 5a 82 00");
    OSCon::Print("");
    for (int i = 0; i < sizeof(key); i += 16)
    {
        OSCon::Print("56 5A 86 00");
        OSCon::Print("56 5A 82 00");
        OSCon::Print("56 5E ef 00");
        OSCon::Print("56 5A A2 00");
        OSCon::Print("56 5A 82 00");
        OSCon::Print("56 58 01 00");
        OSCon::Print("56 59 %02x 00", key[i+0]);
        OSCon::Print("56 59 %02x 00", key[i+1]);
        OSCon::Print("56 59 %02x 00", key[i+2]);
        OSCon::Print("56 59 %02x 00", key[i+3]);
        OSCon::Print("56 59 %02x 00", key[i+4]);
        OSCon::Print("56 59 %02x 00", key[i+5]);
        OSCon::Print("56 59 %02x 00", key[i+6]);
        OSCon::Print("56 59 %02x 00", key[i+7]);
        OSCon::Print("56 59 %02x 00", key[i+8]);
        OSCon::Print("56 59 %02x 00", key[i+9]);
        OSCon::Print("56 59 %02x 00", key[i+10]);
        OSCon::Print("56 59 %02x 00", key[i+11]);
        OSCon::Print("56 59 %02x 00", key[i+12]);
        OSCon::Print("56 59 %02x 00", key[i+13]);
        OSCon::Print("56 59 %02x 00", key[i+14]);
        OSCon::Print("56 59 %02x 00", key[i+15]);
        OSCon::Print("56 5B %02x 00", (addr >> 16)&0xff);
        OSCon::Print("56 5C %02x 00", (addr >>  8)&0xff);
        OSCon::Print("56 5D %02x 00", (addr >>  0)&0xff);
        OSCon::Print("56 5E E0 00");
        OSCon::Print("56 5A 92 00");
        OSCon::Print("56 5A 82 00");
        addr += 16;
    }
    OSCon::Print("");
    OSCon::Print("56 5a 8a 00");
    OSCon::Print("56 5a 82 00");
    OSCon::Print("56 FF 90 00");
    OSCon::Print("56 02 DF 00");
    OSCon::Print("56 02 FF 00");

    return true;
}

// TESTUNIT(Resamplerate, 2, "Resamplerate <insr> <outsr>")
// {
//     Resampler rsp;
//     WavFile inWav;
//     WavFile outWav;
//     int insr = 16000;
//     int outsr = 32000;
//     int channel;
//     int framebyte;
//     size_t outLens;
//     int16_t buffer[480*20];
//     int16_t buffer_out[480*20];
// 
//     insr  = atoi(args[0]);
//     outsr = atoi(args[1]);
// 
//     inWav.Open("audio.wav");
//     outWav.Create("audio_out.wav", outsr, inWav.GetChannel(), 16);
// 
//     insr = inWav.GetSampleRate();
//     channel = inWav.GetChannel();
//     framebyte = insr * channel * 2 / 1000 * 10;
//     rsp.Reset(insr/1000*1000, outsr, channel);
//     while (inWav.Read((unsigned char*)buffer, framebyte) > 0)
//     {
//         rsp.Push((int16_t*)buffer, framebyte / 2, buffer_out, 480 * 5, outLens);
//         outWav.Write((unsigned char*)buffer_out, outLens * 2);
//     }
//     inWav.Close();
//     outWav.Close();
// 
//     return 0;
// }

TESTUNIT(AudioGen, 0, "AudioGen")
{
    const char* strName[] = {
        "AudioStart",
        "AudioNow",
        "AudioSection0",
        "AudioSection1",
        "AudioSection2",
        "AudioSection3",
        "AudioSection4",
        "AudioSection5",
        "AudioSection6",
        "AudioSection7",
        "AudioNumber0",
        "AudioNumber1",
        "AudioNumber2",
        "AudioNumber3",
        "AudioNumber4",
        "AudioNumber5",
        "AudioNumber6",
        "AudioNumber7",
        "AudioNumber8",
        "AudioNumber9",
        "AudioNumber10",
        "AudioNumber11",
        "AudioNumber12",
        "AudioEnd",
        "AudioBell",
    };
    char     srcPath[256];
    uint32_t u32DataLen = 0;
    //char 

    FILE* fOut = fopen(".\\source\\AudioData.c", "w");
    for (int i = 0; i < sizeof(strName) / sizeof(strName[0]); i++)
    {
        sprintf(srcPath, ".\\audio\\%s.wav", strName[i]);
        WavFile wavFile;
        wavFile.Open(srcPath);
        unsigned char* pData = new unsigned char[wavFile.GetDataLength()];
        wavFile.Read(pData, wavFile.GetDataLength());
        wavFile.Close();

        uint32_t u32FileSize = (wavFile.GetDataLength() & 0xFFFFFFFC);
        fprintf(fOut, "// %s %dbytes\n", strName[i], u32FileSize);
        fprintf(fOut, "const unsigned char %s[] =\n{\n", strName[i]);
        fprintf(fOut, "    0x%02x, 0x%02x, 0x%02x, 0x%02x, //size\n", 
            (u32FileSize >>  0) & 0xFF,
            (u32FileSize >>  8) & 0xFF,
            (u32FileSize >> 16) & 0xFF,
            (u32FileSize >> 24) & 0xFF);
        for (int j = 0; j < u32FileSize; j++)
        {
            if (j % 16 == 0)
                fprintf(fOut, "    ");
            fprintf(fOut, "0x%02x, ", pData[j]);
            if (j % 16 == 15)
                fprintf(fOut, "\n");
        }
        fprintf(fOut, "\n};\n");
        u32DataLen += wavFile.GetDataLength();
        delete[] pData;
    }
    fclose(fOut);

    OSCon::Print("Total Data Length:%u\n", u32DataLen);

    return 0;
}

TESTUNIT(AudioTest, 0, "AudioTest")
{
    const unsigned char* const pAudioHour0[]  = { AudioStart, AudioNow, AudioSection7, AudioNumber0,  AudioEnd };
    const unsigned char* const pAudioHour1[]  = { AudioStart, AudioNow, AudioSection7, AudioNumber1,  AudioEnd, AudioBell };
    const unsigned char* const pAudioHour2[]  = { AudioStart, AudioNow, AudioSection7, AudioNumber2,  AudioEnd, AudioBell, AudioBell};
    const unsigned char* const pAudioHour3[]  = { AudioStart, AudioNow, AudioSection7, AudioNumber3,  AudioEnd, AudioBell, AudioBell, AudioBell};
    const unsigned char* const pAudioHour4[]  = { AudioStart, AudioNow, AudioSection0, AudioNumber4,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell};
    const unsigned char* const pAudioHour5[]  = { AudioStart, AudioNow, AudioSection0, AudioNumber5,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell};
    const unsigned char* const pAudioHour6[]  = { AudioStart, AudioNow, AudioSection1, AudioNumber6,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell};
    const unsigned char* const pAudioHour7[]  = { AudioStart, AudioNow, AudioSection1, AudioNumber7,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell};
    const unsigned char* const pAudioHour8[]  = { AudioStart, AudioNow, AudioSection2, AudioNumber8,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell, AudioBell};
    const unsigned char* const pAudioHour9[]  = { AudioStart, AudioNow, AudioSection2, AudioNumber9,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell };
    const unsigned char* const pAudioHour10[] = { AudioStart, AudioNow, AudioSection2, AudioNumber10, AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell };
    const unsigned char* const pAudioHour11[] = { AudioStart, AudioNow, AudioSection2, AudioNumber11, AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell };
    const unsigned char* const pAudioHour12[] = { AudioStart, AudioNow, AudioSection3, AudioNumber12, AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell , AudioBell };
    const unsigned char* const pAudioHour13[] = { AudioStart, AudioNow, AudioSection3, AudioNumber1,  AudioEnd, AudioBell };
    const unsigned char* const pAudioHour14[] = { AudioStart, AudioNow, AudioSection4, AudioNumber2,  AudioEnd, AudioBell, AudioBell };
    const unsigned char* const pAudioHour15[] = { AudioStart, AudioNow, AudioSection4, AudioNumber3,  AudioEnd, AudioBell, AudioBell, AudioBell };
    const unsigned char* const pAudioHour16[] = { AudioStart, AudioNow, AudioSection4, AudioNumber4,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell };
    const unsigned char* const pAudioHour17[] = { AudioStart, AudioNow, AudioSection4, AudioNumber5,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell };
    const unsigned char* const pAudioHour18[] = { AudioStart, AudioNow, AudioSection5, AudioNumber6,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell };
    const unsigned char* const pAudioHour19[] = { AudioStart, AudioNow, AudioSection5, AudioNumber7,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell };
    const unsigned char* const pAudioHour20[] = { AudioStart, AudioNow, AudioSection6, AudioNumber8,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell, AudioBell };
    const unsigned char* const pAudioHour21[] = { AudioStart, AudioNow, AudioSection6, AudioNumber9,  AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell };
    const unsigned char* const pAudioHour22[] = { AudioStart, AudioNow, AudioSection6, AudioNumber10, AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell };
    const unsigned char* const pAudioHour23[] = { AudioStart, AudioNow, AudioSection6, AudioNumber11, AudioEnd, AudioBell, AudioBell, AudioBell,
        AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell };
    //const unsigned char* const pAudioHour24[] = { AudioStart, AudioNow, AudioSection5, AudioNumber12, AudioEnd, AudioBell, AudioBell, AudioBell,
    //    AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell, AudioBell , AudioBell };

    const struct
    {
        uint32_t u32Num;
        const unsigned char* const* pAudio;
    }pAudioTab[] = {
        { sizeof(pAudioHour0  )/sizeof(unsigned char*), pAudioHour0  },
        { sizeof(pAudioHour1  )/sizeof(unsigned char*), pAudioHour1  },
        { sizeof(pAudioHour2  )/sizeof(unsigned char*), pAudioHour2  },
        { sizeof(pAudioHour3  )/sizeof(unsigned char*), pAudioHour3  },
        { sizeof(pAudioHour4  )/sizeof(unsigned char*), pAudioHour4  },
        { sizeof(pAudioHour5  )/sizeof(unsigned char*), pAudioHour5  },
        { sizeof(pAudioHour6  )/sizeof(unsigned char*), pAudioHour6  },
        { sizeof(pAudioHour7  )/sizeof(unsigned char*), pAudioHour7  },
        { sizeof(pAudioHour8  )/sizeof(unsigned char*), pAudioHour8  },
        { sizeof(pAudioHour9  )/sizeof(unsigned char*), pAudioHour9  },
        { sizeof(pAudioHour10 )/sizeof(unsigned char*), pAudioHour10 },
        { sizeof(pAudioHour11 )/sizeof(unsigned char*), pAudioHour11 },
        { sizeof(pAudioHour12 )/sizeof(unsigned char*), pAudioHour12 },
        { sizeof(pAudioHour13 )/sizeof(unsigned char*), pAudioHour13 },
        { sizeof(pAudioHour14 )/sizeof(unsigned char*), pAudioHour14 },
        { sizeof(pAudioHour15 )/sizeof(unsigned char*), pAudioHour15 },
        { sizeof(pAudioHour16 )/sizeof(unsigned char*), pAudioHour16 },
        { sizeof(pAudioHour17 )/sizeof(unsigned char*), pAudioHour17 },
        { sizeof(pAudioHour18 )/sizeof(unsigned char*), pAudioHour18 },
        { sizeof(pAudioHour19 )/sizeof(unsigned char*), pAudioHour19 },
        { sizeof(pAudioHour20 )/sizeof(unsigned char*), pAudioHour20 },
        { sizeof(pAudioHour21 )/sizeof(unsigned char*), pAudioHour21 },
        { sizeof(pAudioHour22 )/sizeof(unsigned char*), pAudioHour22 },
        { sizeof(pAudioHour23 )/sizeof(unsigned char*), pAudioHour23 },
//        { sizeof(pAudioHour24 )/sizeof(unsigned char*), pAudioHour24 },
    };

    for (int h = 0; h < 24; h++)
    {
        WavFile wavFile;
        char path[256];
        sprintf(path, "hour%d_out.wav", h);
#if 0
        wavFile.Create(path, 8000, 1, 16);

        unsigned char* pData;
        pData = (unsigned char*)pAudio[h][0];
        wavFile.Write((unsigned char*)(pData + 44), *((unsigned int*)pData + 10));
        pData = (unsigned char*)pAudio[h][1];
        wavFile.Write((unsigned char*)(pData + 44), *((unsigned int*)pData + 10));
        pData = (unsigned char*)pAudio[h][2];
        wavFile.Write((unsigned char*)(pData + 44), *((unsigned int*)pData + 10));
        pData = (unsigned char*)pAudio[h][3];
        wavFile.Write((unsigned char*)(pData + 44), *((unsigned int*)pData + 10));
#else
        wavFile.Create(path, 8000, 2, 16);
        signed short s16Frame[1600];
        unsigned char* pData = (unsigned char*)pAudioTab[h].pAudio[0];
        unsigned int u32Index = 0;
        unsigned int u32Offset = 2;
        while(1)
        {
            for (int k = 0; k < 1600 / 2; k++)
            {
                s16Frame[2 * k + 0] = *((short*)pData + u32Offset);
                s16Frame[2 * k + 1] = -1 * s16Frame[2 * k + 0];
                u32Offset++;
                if(u32Offset*2 > *(unsigned int*)pData)
                {
                    u32Index++;
                    u32Offset = 2;
                    pData = (unsigned char*)pAudioTab[h].pAudio[u32Index];
                    if (u32Index >= pAudioTab[h].u32Num)
                    {
                        break;
                    }
                }
            }
            wavFile.Write((unsigned char*)s16Frame, sizeof(s16Frame));
            if (u32Index >= pAudioTab[h].u32Num)
                break;
        }
#endif
        wavFile.Close();
    }

    return 0;
}

auto log_2(uint32_t x)
{ // also unsigned int
    int32_t dbVal = 0;
    if (x == 1U)
    {
        dbVal = 0;
    }
    else
    {
        float q = (float)x;
        dbVal = ((*(int*)&q) >> 23) & 31;
        dbVal += 2;
    }

    dbVal = 90 - 3 * dbVal; //取反，返回正值
    return dbVal;
}

TESTUNIT(RMSTest, 0, "RMSTest")
{
    uint16_t u16RmsValue[16] = {0x4000, 0x7fff, 0x3fff, 0x1fff, 0x0fff, 0x07ff, 0x03ff, 0x01ff, 0x00ff, 0x007f, 0x003f, 0x001f, 0x000f, 0x0007, 0x0003, 0x0001 } ;
    int16_t  s16DbValue[16] = { 0 };
    for (auto i = 0; i < 16; i++)
    {
        s16DbValue[i] = log_2(u16RmsValue[i]* u16RmsValue[i]);
        OSCon::Print("RMS:%04x Db:%d\n", u16RmsValue[i], s16DbValue[i]);
    }

    return true;
}

OSCon consle;

int main()
{
    OSCon::Init();
    OSFile::Init();


    OSCon::Print("Build-at:%s %d\r\n", __DATE__, __TIME__);
    consle.Run("RUN:");

    system("PAUSE");
}
